﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace XYZShell.Helper
{

	public class FlowBufferEventArgs<T> : EventArgs
	{
		public T Value
		{
			get;
			set;
		}
	}
	public class FlowBuffer<T>
	{

		AutoResetEvent evt = new AutoResetEvent( false );
		private readonly object mutex = new object();
		//private List<T> buffer_ = new List<T>();
		private Queue<T> buffer_ = new Queue<T>();
		public event EventHandler<FlowBufferEventArgs<T>> DataArrived;
		private bool quit_ = false;

		public int Count
		{
			get
			{
				//Monitor.Enter( mutex );
				int rtn = buffer_.Count;
				//Monitor.Exit( mutex );
				return rtn;
			}

		}
		public FlowBuffer( EventHandler<FlowBufferEventArgs<T>> queueCallback )
		{
			this.DataArrived = queueCallback;
			Thread tread = new Thread( new ThreadStart( ThreadLoop ) );
			tread.Start();
		}
		public FlowBuffer()
		{
			Thread tread = new Thread( new ThreadStart( ThreadLoop ) );
			tread.Start();
		}
		protected void OnDataArrived( FlowBufferEventArgs<T> e )
		{
			if (DataArrived != null)
			{
				DataArrived( this, e );
			}
		}
		void ThreadLoop()
		{
			while (true)
			{
				FlowBufferEventArgs<T> e = null;
				lock (mutex)
				{

					if (buffer_.Count == 0)
					{
						Monitor.Wait( mutex );
					}
					if (quit_)
					{
						break;
					}
					e = new FlowBufferEventArgs<T>();
					e.Value = buffer_.Dequeue();
				}


				try
				{
					if (null != e)
					{
						OnDataArrived( e );
					}

				}
				catch (System.Exception ex)
				{

				}

			}


		}
		public void Add( T item )
		{
			lock (mutex)
			{
				buffer_.Enqueue( item );
				Monitor.PulseAll( mutex );
			}
		}
		public void AddRange( IEnumerable<T> items )
		{

			lock (mutex)
			{
				foreach (var item in items)
				{
					buffer_.Enqueue( item );
				}
				Monitor.PulseAll( mutex );
			}
		}
		public void Quit()
		{
			quit_ = true;
			Monitor.PulseAll( mutex );
		}
	}
}
